﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using Behaviorize.CodeGenerator.CodeGenerating;
using Behaviorize.CodeGenerator.FileIO;
using Behaviorize.CodeGenerator.Properties;
using Behaviorize.CodeGenerator.TextInterpretation;
using Behaviorize.CodeGenerator.VsProject;
using EnvDTE;
using Microsoft.VisualStudio.Shell;
using VSLangProj80;

namespace Behaviorize.CodeGenerator
{
	[Guid("02850A98-0988-4C6A-B46D-7B748C166207")]
	[ComVisible(true)]
	[CodeGeneratorRegistration(typeof (BehaviorizeClassGenerator), "Behaviorize C# class generator", vsContextGuids.vsContextGuidVCSProject,
		GeneratesDesignTimeSource = true)]
	[ProvideObject(typeof (BehaviorizeClassGenerator))]
	public class BehaviorizeClassGenerator : BaseCodeGeneratorWithSite
	{
		private readonly IFileWriter _fileWriter;
		private readonly IFileReader _fileReader;
		private readonly IProjectItemService _projectItemService;

#pragma warning disable 0414
		internal static string name = "BehaviorizeClassGenerator";
#pragma warning restore 0414

		public BehaviorizeClassGenerator()
		{
			_fileWriter = ServiceLocator.Resolve<IFileWriter>();
			_fileReader = ServiceLocator.Resolve<IFileReader>();
			_projectItemService = ServiceLocator.Resolve<IProjectItemService>();
		}

		protected override string GetDefaultExtension()
		{
			return ".feature.cs";
		}

		public override byte[] GenerateCode(string inputFileContent)
		{
			CodeModel.Feature feature = Interpreter.ParseSpecificationText(inputFileContent);

			if (feature != null)
			{
				ProjectItem projectItem = _projectItemService.GetProjectItem(this);

				string classContents = GenerateClassFile(feature, projectItem);
				return Encoding.UTF8.GetBytes(classContents);
			}

			return null;
		}

		private string GenerateClassFile(CodeModel.Feature feature, ProjectItem featureSpecificationFile)
		{
			string filename = GetFilename(featureSpecificationFile, GetDefaultExtension());
			string nameSpace = _projectItemService.GetNamespace(this);
			string classStubCode = CreateClassStubCode(feature, nameSpace, "ClassTemplate");

			if (!_fileReader.FileExists(filename))
			{
				_fileWriter.WriteFile(filename, classStubCode);
			}

			ProjectItem subItem = _projectItemService.GetSubItem(featureSpecificationFile, filename)
			                      ?? featureSpecificationFile.ProjectItems.AddFromFile(filename);

			subItem.Open()
			subItem.Save();
			
			return ClassCodeGenerator.CreateOrUpdateCode(feature, subItem, nameSpace);

			//if (!subItem.IsOpen[Constants.vsViewKindCode]) subItem.Save();
		}

		private static string GetFilename(ProjectItem featureSpecificationFile, string extension)
		{
			string parentItemFilename = featureSpecificationFile.get_FileNames(0);

			if (parentItemFilename.EndsWith(".feature"))
			{
				return parentItemFilename.Substring(0, parentItemFilename.Length - 8) + extension;
			}

			return parentItemFilename + extension;
		}

		private static string CreateClassStubCode(CodeModel.Feature feature, string fileNameSpace, string template)
		{
			var classTemplate = (string)Resources.ResourceManager.GetObject(template);
			var replacements = new Dictionary<string, string>
				{
					{"$namespace$", fileNameSpace},
					{"$featurename$", feature.Name.AsPascal()},
				};

			foreach (string token in replacements.Keys)
			{
				classTemplate = classTemplate.Replace(token, replacements[token]);
			}

			return classTemplate;
		}
	}
}